use std::sync::Condvar;
use std::sync::Mutex;
use std::sync::atomic::AtomicU64;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
pub struct ThreadSafeVariable {
    value: AtomicU64,
    max_value: u64,
    lock: Mutex<()>,
    condvar: Condvar,
}
impl ThreadSafeVariable{
    pub fn new(max_value: u64) -> Self {
        ThreadSafeVariable {
            value: AtomicU64::new(0),
            max_value,
            lock: Mutex::new(()),
            condvar: Condvar::new(),
        }
    }
    pub fn add(&self,i:u64){
        let mut _guard = self.lock.lock().unwrap();
        if i > self.max_value{
            loop{
            if self.value.load(Ordering::Relaxed) == 0{
                self.value.fetch_add(i,Ordering::SeqCst);
                self.condvar.notify_all();
                drop(_guard);
                break;
            }else{
                _guard = self.condvar.wait(_guard).unwrap();
            }
            }
        }else{
            loop{
            if self.value.load(Ordering::Relaxed) + i <self.max_value{
                self.value.fetch_add(i,Ordering::SeqCst);
                self.condvar.notify_all();
                drop(_guard);
                break;
            }else{
                _guard = self.condvar.wait(_guard).unwrap();
            }
            }
        }
    }
    pub fn sub(&self,i:u64){
        let mut _guard = self.lock.lock().unwrap();
        self.value.fetch_sub(i,Ordering::SeqCst);
        self.condvar.notify_all();
        drop(_guard);
    }
}